import { Injectable, Logger, NotFoundException, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Attachment } from '../../contents/entities/attachment.entity';
import { ObsService } from './obs.service';
import { AttachmentConfirmDto } from '../dto/attachment-confirm.dto';
import * as path from 'path';
import * as mime from 'mime-types';
import { AttachmentResponseDto } from '../dto/attachment-response.dto';

@Injectable()
export class AttachmentsService {
  private readonly logger = new Logger(AttachmentsService.name);

  constructor(
    @InjectRepository(Attachment)
    private readonly attachmentRepository: Repository<Attachment>,
    private readonly obsService: ObsService,
  ) {}

  /**
   * Detect file type based on file extension
   * @param fileName File name with extension
   * @returns MIME type or undefined
   */
  private detectFileType(fileName: string): string | undefined {
    const extension = path.extname(fileName).toLowerCase();
    return mime.lookup(extension) || undefined;
  }

  /**
   * Map an attachment entity to a response DTO
   * @param attachment The attachment entity
   * @returns The attachment response DTO
   */
  private mapToResponseDto(attachment: Attachment): AttachmentResponseDto {
    return {
      id: attachment.id,
      fileUrl: attachment.fileUrl,
      filename: attachment.fileName,
      createdBy: attachment.createdBy,
      createdAt: attachment.createdAt,
    };
  }

  /**
   * Create a new attachment record
   * @param attachmentData The attachment data
   * @returns The created attachment
   */
  async createAttachment(attachmentData: AttachmentConfirmDto): Promise<AttachmentResponseDto> {
    try {
      // Validate the file URL
      if (!this.obsService.validateFileUrl(attachmentData.fileUrl)) {
        throw new BadRequestException('Invalid file URL');
      }

      // Determine file type based on file extension
      const fileType = this.detectFileType(attachmentData.filename);

      // Create a new attachment entity
      const attachment = new Attachment();
      attachment.fileUrl = attachmentData.fileUrl;
      attachment.fileName = attachmentData.filename;
      attachment.attachmentType = fileType; // Set the attachment type based on file extension
      // In a real implementation, you would get the user ID from the request
      attachment.createdBy = 'user-id'; // This should be replaced with the actual user ID

      // Save the attachment to the database
      const savedAttachment = await this.attachmentRepository.save(attachment);
      this.logger.debug(`Attachment confirmed and saved with ID: ${savedAttachment.id}`);

      // Map the entity to the response DTO
      return this.mapToResponseDto(savedAttachment);
    } catch (error) {
      this.logger.error(`Failed to create attachment: ${error.message}`, error.stack);
      if (error instanceof BadRequestException) {
        throw error;
      }
      throw new Error('Failed to create attachment record');
    }
  }

  /**
   * Find an attachment by ID
   * @param id The attachment ID
   * @returns The attachment or null if not found
   */
  async findById(id: string): Promise<AttachmentResponseDto> {
    try {
      const attachment = await this.attachmentRepository.findOne({ where: { id } });

      if (!attachment) {
        throw new NotFoundException(`Attachment with ID ${id} not found`);
      }

      return this.mapToResponseDto(attachment);
    } catch (error) {
      this.logger.error(`Failed to find attachment: ${error.message}`, error.stack);
      throw error;
    }
  }

  /**
   * Get attachments by content ID
   * @param contentId Content ID
   * @returns Array of attachment records
   */
  async findByContentId(contentId: string): Promise<Attachment[]> {
    return this.attachmentRepository.find({ where: { contentId } });
  }
}
